Представляем структуру лекции — от базовых понятий процесса и потока к механизмам межпроцессного взаимодействия. Обратите внимание аудитории на практическую часть в конце.
Процесс — это не программа. Программа — файл на диске, процесс — её живой экземпляр с ресурсами. Аналогия: программа — рецепт, процесс — процесс готовки.
PCB — «паспорт» процесса для ядра. Без него ядро не может управлять процессом: планировать, приостанавливать, возобновлять. PCB хранится в памяти ядра.
Поток — «мини-процесс» внутри процесса. Ключевой момент: потоки разделяют память, что делает обмен данныся быстрым, но создаёт проблемы синхронизации.
Эта таблица — шпаргалка для экзамена. Акцент: сбой потока может «убить» весь процесс — ключевое отличие от изолированности процессов.
Приведите примеры: браузер использует потоки для вкладок, IDE — для компиляции и автодополнения. Однопоточный процесс — классическая программа из курса программирования.
Левая колонка — то, что потоки делят (и из-за чего возможны гонки данных). Правая — что у каждого потока своё (и что нужно сохранять при переключении контекста).
Переходим к архитектурным моделям. Три модели — каждая со своими компромиссами. Это фундамент для понимания реализации потоков в конкретных ОС.
Исторически первая модель. Быстрая, но уязвимая — один блокирующий вызов останавливает всё. Спросите аудиторию: в каких случаях это приемлемо?
Модель Linux и Windows сегодня. Настоящий параллелизм на многоядерных системах, но за это приходится платить расходом ресурсов и ограничением числа потоков.
Компромиссная модель — сложна в реализации, но гибка. На практике многие системы эволюционировали к модели «один к одному», отказавшись от этой модели.
Сводная таблица для сравнения. «Многие к одному» — по сути потоки уровня пользователя, «один к одному» — ядерные потоки. Запомните компромиссы каждой модели.
Проиллюстрируйте каждый пункт примером. Отзывчивость — UI не зависает. Экономичность — создание потока в 10–100 раз дешевле процесса.
pthread — стандартный API потоков в UNIX. Используем на практических занятиях. Запомните основные функции — понадобятся для лабораторных.
Пользовательские потоки — библиотека берёт на себя планирование, ядро ничего не знает. Быстро, но ограниченно: блокирующий вызов стопит весь процесс.
Главная проблема — блокирующие системные вызовы. Если один поток вызывает read(), весь процесс ждёт. Обёртки и неблокирующий I/O — обходные пути.
Ядро управляет потоками напрямую — блокировка одного не мешает другим. Но каждое переключение — системный вызов, а это накладные расходы.
Наглядное сравнение двух подходов. Пользовательские — быстрые, но ограниченные. Ядерные — полноценные, но с накладными расходами на системные вызовы.
Попытка получить лучшее от обоих миров. Исторически интересна, но большинство современных ОС выбрали модель «один к одному».
Уникальная особенность Linux — единый вызов для создания и процессов, и потоков. Разница только в флагах. Элегантное архитектурное решение.
fork() — тяжёлый, clone() — гибкий. Подчеркните: pthread_create в Linux внутри использует clone() с флагом CLONE_VM.
В Linux нет отдельного понятия «поток» — всё задачи. Унифицированная модель. PID и tid — разные вещи, что иногда путает начинающих.
Переходим ко второй большой теме. IPC — фундамент для микросервисов, клиент-серверных приложений, конвейеров оболочки.
Два класса механизмов. Передача данных — данные копируются. Разделяемые ресурсы — процессы работают с одной памятью напрямую.
Важное различие: каналы дают и коммуникацию, и синхронизацию. Семафоры — только синхронизацию. Выбор механизма зависит от задачи.
Два стандарта IPC. System V — старше, POSIX — современнее и удобнее. На практике стоит предпочитать POSIX, но System V всё ещё встречается в legacy-коде.
Каналы — простейший IPC. Shell-конвейер `cmd1 | cmd2` — это pipe. Ограничение: только между родственными процессами (после fork).
Разберите код построчно. Обратите внимание: оба конца pipe нужно закрывать в каждом процессе — частая ошибка студентов.
FIFO решает главное ограничение pipe — работает между любыми процессами через имя в файловой системе. Но по-прежнему однонаправленный.
Очереди сообщений дают структурированный обмен — каждое сообщение имеет тип. Процесс может выбирать, какие сообщения читать, что отличает их от каналов.
Самый быстрый IPC — нет копирования данных. Но требуется ручная синхронизация — тема следующей лекции. Подчеркните этот ключевой компромисс.
Простой пример: создаём сегмент, подключаем к адресу, работаем как с обычной памятью. В реальном коде необходима синхронизация через семафоры.
mmap — альтернатива System V shm. Отображает файл в память: даёт и IPC, и работу с файлами. Часто предпочтительнее shmget/shmat.
Семафоры — механизм синхронизации, а не передачи данных. Операции P и V — атомарны. Подробно разберём в следующей лекции 07.
Сигналы — простейший и самый ограниченный механизм. Полезны для уведомлений, но не для передачи данных. SIGUSR1/SIGUSR2 — для пользовательских нужд.
Сокеты — самый универсальный механизм IPC. Работают и локально, и по сети. Unix domain sockets — для быстрой локальной IPC без сетевого оверхеда.
Практический пример создания двух потоков. Обратите внимание: pthread_join обязателен — без него main завершится раньше потоков.